#the handler for the millenium catalog

#the parameters that are in the dictionary are as follows:
#       searchscope
#       name
#       url
#       downconvertisbn13
#       options
#       sid
#       contextmenuoptions
#       urlregexp
#       cues
#       includeincontextmenu

import sys
# add directory in which script is located to python path
script_dir = "/".join(__file__.split("/")[:-1])
if script_dir == "":
    script_dir = "."
if script_dir not in sys.path:
    sys.path.append(script_dir)

import re, urllib, traceback
from collections import defaultdict
from django.utils import simplejson

marcrecordformat = re.compile('<pre>\n(LEADER(.|\n)*)<\/pre>', re.I)
marclineformat = re.compile('^(\d{3}) (\d| )(\d| ) (.*)((?:\n[ ]{7}(.+))*)$', re.MULTILINE)
subfieldformat = re.compile('(?:|\|(\S))([^|\n]+)(?=\||$)')
locationsformat = re.compile('<!-- field [\$1] -->([\s\S]*?)<\/')
holdingsformat = re.compile('<!-- field % -->([^<]*)<')
htmltags = re.compile('<\/?[^>]*>')
nbsp = re.compile('&nbsp;|&#160;')


def parseIII(response):
    """
        Scraping III, for the umpteenth time
    """
    def clean(s):
        return nbsp.sub(" ", htmltags.sub("", s)).strip()

    try:
        marcbody = marcrecordformat.search(response).group(1)
        marc = defaultdict(list)

        for line in marclineformat.finditer(marcbody):
            (fcode, ind1, ind2, firstline, nextlines, _) = line.groups()
            nextlines = nextlines or ""
            turnnewlineintospace = fcode == '245'
            content = firstline \
                + re.sub('\n[ ]{7}', ("", " ")[turnnewlineintospace], nextlines)
            content = re.sub('\s+', ' ', content).strip()

            subfields = defaultdict(list)
            for subfield in subfieldformat.finditer(content):
                (subcode, subfieldvalue) = subfield.groups()
                subcode = subcode or 'a'
                subfields[subcode].append(subfieldvalue.strip())

            marc[fcode].append({ 'i1': ind1, 'i2': ind2, 'sf' : subfields })
        return {
            'marc': marc,
            'locations': [ clean(l.group(1)) for l in locationsformat.finditer(response) ],
            'holdings': [ clean(h.group(1)) for h in holdingsformat.finditer(response) ]
        }

    except:
        #traceback.print_exc()
        pass


def validateIII(marc, sterm):
    def OrList(list):
        return reduce(lambda x, y: x or y, list, False)

    if not marc:
        return False

    try:
        if sterm.startswith('.b'):
            return True

        term = sterm[1:].lower()
        if sterm.startswith('i'):
            return OrList([  f['sf'].has_key('a') and f['sf']['a'][0].lower().startswith(term) \
                            for f in marc['020']]) \
                or OrList([  f['sf'].has_key('z') and f['sf']['z'][0].lower().startswith(term) \
                            for f in marc['020']]) \
                or OrList([ f['sf']['a'][0].lower().replace("-", "").startswith(term) \
                            for f in marc['022']])

        if sterm.startswith('o'):
            return OrList([ f['sf']['a'][0].lower().startswith(term) for f in marc['001']])

        if sterm.startswith('t'):
            return True # XXX

        return False
    except KeyError:
        return False
    except IndexError:
        return False


def makeIIISearch(opacbase, sterm):
    return opacbase + "/" + sterm + "/" + sterm + "/1,1,1,E/marc&FF=" + sterm

def handler(millenium, sterm):
    opacbase = millenium['url'] + "/search"
    if millenium.has_key('searchscope'):
        opacbase += "~S" + millenium['searchscope']
    url = makeIIISearch(opacbase, sterm)
    iiiresponse = urllib.urlopen(url).read()
    marc = parseIII(iiiresponse)
    return marc 
    #marcrecords = [ ]
    #if marc and validateIII(marc['marc'], sterm):
    #    marcrecords.append(marc)

    #return {
    #    'results' : marcrecords,
    #    'searchterm' : sterm,
    #    'recordurl' : url
    #}
    #return iiiresponse 
